Packages

Introduction

Build Website Website Website Website

Sliding windows

import sys
sys.path.insert(1, 'libs/')

import dynfc as dyn
import numpy as np
from numpy.random import seed, rand
import scipy as sc
from scipy import io
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.cbook as cbook
import matplotlib.cm as cm
import matplotlib.patches as patches

font = {'weight' : 'regular',
        'size'   : 24}
plt.rc('font', **font)

ts = sc.io.loadmat('data/ts.mat')['ts']
ts = ts.transpose()

corr_mats, idx = dyn.corr_slide(ts,300,50)

idx.shape
> (24,)
a = [1,1,1,1,1.6]

fig,ax = plt.subplots(1)
fig.set_figheight(10)
fig.set_figwidth(20)
plt.style.use('tableau-colorblind10')
for i in range(5):
    
    plt.plot(2*i*a[i] + ts[i,]/1.4)   
    
> [<matplotlib.lines.Line2D object at 0x7f8232790a20>]
> [<matplotlib.lines.Line2D object at 0x7f8232779c18>]
> [<matplotlib.lines.Line2D object at 0x7f823277e320>]
> [<matplotlib.lines.Line2D object at 0x7f823277e358>]
> [<matplotlib.lines.Line2D object at 0x7f8232779dd8>]
plt.xlabel('Time [TRs]')
> Text(0.5, 0, 'Time [TRs]')
plt.ylabel('BOLD')
> Text(0, 0.5, 'BOLD')
ax.tick_params(left=False)
ax.set_yticklabels([])
> [Text(0, -2.0, ''), Text(0, 0.0, ''), Text(0, 2.0, ''), Text(0, 4.0, ''), Text(0, 6.0, ''), Text(0, 8.0, ''), Text(0, 10.0, ''), Text(0, 12.0, ''), Text(0, 14.0, '')]
ax.set_ylim(-3,15.4)
> (-3.0, 15.4)
ax.set_xlim(0,1200)
> (0.0, 1200.0)
rect = patches.Rectangle((idx[0],-2.8),300,18,linewidth=4,edgecolor='#595959',facecolor='none')
ax.add_patch(rect)
> <matplotlib.patches.Rectangle object at 0x7f81f94d10f0>
rect = patches.Rectangle((idx[5],-2.8),300,18,linewidth=4,edgecolor='#A56B6B',facecolor='none')
ax.add_patch(rect)
> <matplotlib.patches.Rectangle object at 0x7f81f94d1390>
rect = patches.Rectangle((idx[9],-2.8),300,18,linewidth=4,edgecolor='#CE3E3E',facecolor='none')
ax.add_patch(rect)
> <matplotlib.patches.Rectangle object at 0x7f81f94d16a0>
rect = patches.Rectangle((idx[16],-2.8),300,18,linewidth=4,edgecolor='#FF0000',facecolor='none')
ax.add_patch(rect)
> <matplotlib.patches.Rectangle object at 0x7f81f94d19b0>
plt.show()

import sys
sys.path.insert(1, 'libs/')

import dynfc as dyn
import numpy as np
from numpy.random import seed, rand
import scipy as sc
from scipy import io
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.cbook as cbook
import matplotlib.cm as cm
import matplotlib.patches as patches

aa = plt.figure(figsize = [6,6])
ax = sns.heatmap(corr_mats[:,:,0], 
                 cmap = "RdBu_r", 
                 vmin = -1, 
                 vmax = 1, 
                 square = True, 
                 cbar = False)
ax.axis('off')
> (0.0, 200.0, 200.0, 0.0)
ax.tick_params(left=False, bottom=False)
    
plt.show()

aa = plt.figure(figsize = [6,6])
ax = sns.heatmap(corr_mats[:,:,5], 
                 cmap = "RdBu_r", 
                 vmin = -1, 
                 vmax = 1, 
                 square = True, 
                 cbar = False)
ax.axis('off')
> (0.0, 200.0, 200.0, 0.0)
ax.tick_params(left=False, bottom=False)
    
plt.show()

aa = plt.figure(figsize = [6,6])
ax = sns.heatmap(corr_mats[:,:,9], 
                 cmap = "RdBu_r", 
                 vmin = -1, 
                 vmax = 1, 
                 square = True, 
                 cbar = False)
ax.axis('off')
> (0.0, 200.0, 200.0, 0.0)
ax.tick_params(left=False, bottom=False)
    
plt.show()

aa = plt.figure(figsize = [6,6])
ax = sns.heatmap(corr_mats[:,:,16], 
                 cmap = "RdBu_r", 
                 vmin = -1, 
                 vmax = 1, 
                 square = True, 
                 cbar = False)
ax.axis('off')
> (0.0, 200.0, 200.0, 0.0)
ax.tick_params(left=False, bottom=False)
    
plt.show()

Cofluctuations

import sys
sys.path.insert(1, 'libs/')

import numpy as np
import scipy as sc
from scipy import io
import dynfc as dyn
import seaborn as sns
import matplotlib.pyplot as plt

ts = sc.io.loadmat('data/ts.mat')['ts']
ts = ts.transpose()

mat1, rss = dyn.corr_slide(ts,24)
mat1 = mat1[:,:,0]

aa = plt.figure(figsize = [6,6])
ax = sns.heatmap(mat1, 
                 cmap = "RdBu_r", 
                 vmin = -1, 
                 vmax = 1, 
                 square = False, 
                 cbar = True)
ax.axis('off')
> (0.0, 200.0, 200.0, 0.0)
ax.tick_params(left=False, bottom=False)
plt.show()

upt = np.triu_indices(mat1.shape[0], k = 1)
vec = (mat1[upt])

toPlot = np.zeros((vec.shape[0],1))
toPlot[:,0] = vec

aa = plt.figure(figsize = (12/50,4))
ax = sns.heatmap(toPlot[:,0:1], 
                 cmap = "RdBu_r", 
                 vmin = -1, 
                 vmax = 1, 
                 square = False, 
                 cbar = False)
ax.axis('off')
> (0.0, 1.0, 19900.0, 0.0)
plt.show()

edges_series, corr_mats, rss = dyn.cofluct(ts, 24)

aa = plt.figure(figsize = (12,4))
> /Users/runner/Library/r-miniconda/envs/r-reticulate/bin/python:1: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).
ax = sns.heatmap(edges_series, 
                 cmap = "RdBu_r", 
                 vmin = -1, 
                 vmax = 1, 
                 square = False, 
                 cbar = False)
ax.axis('off')
> (0.0, 1200.0, 19900.0, 0.0)
plt.show()

#Phase difference

import sys
sys.path.insert(1, 'libs/')

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from mpl_toolkits.mplot3d import Axes3D

theta = np.linspace(0*np.pi, 8*np.pi, 100)
time = np.linspace(0, 8, 100)
y1 = np.sin(theta)
x1 = np.cos(theta)
y2 = np.sin(theta + np.pi/2)
x2 = np.cos(theta + np.pi/2)
r = time/np.max(time)
ones = np.ones(time.shape[0])

fig = plt.figure()
ax = fig.add_subplot(projection='3d')
plt.style.use('classic')

ax.plot(time, x1, y1, color = '#67001f', linewidth=2)
> [<mpl_toolkits.mplot3d.art3d.Line3D object at 0x7f82c4246ba8>]
ax.plot(time,ones,y1, linestyle = '--', color = '#0f0f0f')
> [<mpl_toolkits.mplot3d.art3d.Line3D object at 0x7f82cbb1ddd8>]
ax.plot(time,x1,-ones, linestyle = '--', color = '#0f0f0f')
> [<mpl_toolkits.mplot3d.art3d.Line3D object at 0x7f82d62d7b00>]
ax.quiver(time,0,0,0, 0.99*x1, 0.99*y1, 
          length = 0.9, 
          normalize = False, 
          arrow_length_ratio = 0.1, 
          alpha = 0.4, 
          color = '#053061')
> <mpl_toolkits.mplot3d.art3d.Line3DCollection object at 0x7f82d62d7668>
ax.text(0.5, 1, 0.5, r'$\sin(\theta)$', fontsize = 20)
> Text(0.5, 1, '$\\sin(\\theta)$')
ax.text(0.5, -1, -1, r'$\cos(\theta)$', fontsize = 20)
> Text(0.5, -1, '$\\cos(\\theta)$')
ax.set_xlabel('Time')
> Text(0.5, 0, 'Time')
ax.set_ylabel('Re')
> Text(0.5, 0, 'Re')
ax.set_zlabel('Im')
> Text(0.5, 0, 'Im')
ax.set_xlim(0,8)
> (0.0, 8.0)
ax.set_ylim(-1,1)
> (-1.0, 1.0)
ax.set_zlim(-1,1)
> (-1.0, 1.0)
plt.show()

colors1 = plt.cm.Reds(np.arange(0,1,0.01))
colors1[:,-1] = np.arange(0,1,0.01)

colors2 = plt.cm.Blues(np.arange(0,1,0.01))
colors2[:,-1] = np.arange(0,1,0.01)

fig = plt.figure(figsize = (12,8))
ax = fig.add_subplot(projection='3d')
plt.style.use('classic')

ax.scatter(time,ones,r*y1, color = colors1, marker = ",", s = 3)
> <mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x7f82cf79f6a0>
ax.scatter(time,r*x1,-ones, color = colors1, marker = ",", s = 3)
> <mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x7f82cbaecb70>
ax.scatter(time,ones,r*y2, color = colors2, marker = ",", s = 3)
> <mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x7f82cbaec6d8>
ax.scatter(time,r*x2,-ones, color = colors2, marker = ",", s = 3)
#ax.plot(time,r*x2,-ones, linestyle = '--', color = colors2[-10,:])
> <mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x7f82cf783748>
ax.quiver(time,0,0,0, 0.99*r*x1, 0.99*r*y1, 
          length = 0.9, 
          normalize = False, 
          arrow_length_ratio = 0.1, 
          alpha = 1, 
          color = colors1)
> <mpl_toolkits.mplot3d.art3d.Line3DCollection object at 0x7f82c4205240>
ax.quiver(time,0,0,0, 0.99*r*x2, 0.99*r*y2, 
          length = 0.9, 
          normalize = False, 
          arrow_length_ratio = 0.1, 
          alpha = 1, 
          color = colors2)
> <mpl_toolkits.mplot3d.art3d.Line3DCollection object at 0x7f82c4205080>
ax.text(0.5, 1, 0.4, r'$A(t)$ $\sin(\theta)$', fontsize = 20)
> Text(0.5, 1, '$A(t)$ $\\sin(\\theta)$')
ax.text(0.5, -0.9, -1, r'$A(t)$ $\cos(\theta)$', fontsize = 20)
> Text(0.5, -0.9, '$A(t)$ $\\cos(\\theta)$')
ax.set_xlabel('Time')
> Text(0.5, 0, 'Time')
ax.set_ylabel('Re')
> Text(0.5, 0, 'Re')
ax.set_zlabel('Im')
> Text(0.5, 0, 'Im')
ax.set_xlim(0,8)
> (0.0, 8.0)
ax.set_ylim(-1,1)
> (-1.0, 1.0)
ax.set_zlim(-1,1)
> (-1.0, 1.0)
plt.show()

x1_vec = x1
x1_vec = x1_vec[99]
y1_vec = y1
y1_vec = y1_vec[99]

x2_vec = x2
x2_vec = x2_vec[99]
y2_vec = y2
y2_vec = y2_vec[99]

x, y = 0.0, 0.0

fig,ax = plt.subplots(1)
fig.set_figheight(6)
fig.set_figwidth(7)
ax.scatter(r*x1,r*y1, color = colors1, marker = ".", s = 100)
> <matplotlib.collections.PathCollection object at 0x7f82d0f65898>
ax.scatter(r*x2,r*y2, color = colors2, marker = ".", s = 100)
> <matplotlib.collections.PathCollection object at 0x7f82d0f65c88>
ax.arrow(0,0,x1_vec,y1_vec, width = 0.015, color = colors1[-1,:], head_width = 0.1)
> <matplotlib.patches.FancyArrow object at 0x7f82c42560f0>
ax.arrow(0,0,x2_vec,y2_vec, width = 0.015, color = colors2[-1,:], head_width = 0.1)
> <matplotlib.patches.FancyArrow object at 0x7f82d0f5d6a0>
ax.add_patch(patches.Arc((x,y), 2.3, 2.3, theta1=0.0, theta2=90.0, linestyle = '--'))
> <matplotlib.patches.Arc object at 0x7f82d0f5d5f8>
ax.text(0.7,1, r'$\mathcal{\Delta\varphi = \frac{\pi}{2}}$', fontsize = 24)
> Text(0.7, 1, '$\\mathcal{\\Delta\\varphi = \\frac{\\pi}{2}}$')
ax.text(1.18*x1_vec,y1_vec, r'$\mathcal{\varphi}_{1}$', fontsize = 20)
> Text(1.18, -9.797174393178826e-16, '$\\mathcal{\\varphi}_{1}$')
ax.text(x2_vec,1.22*y2_vec, r'$\mathcal{\varphi}_{2}$', fontsize = 20)
> Text(-7.354070601250002e-16, 1.22, '$\\mathcal{\\varphi}_{2}$')
ax.set_xlim(-1.35,1.35)
> (-1.35, 1.35)
ax.set_ylim(-1.35,1.35)
> (-1.35, 1.35)
ax.set_xlabel('Re')
> Text(0.5, 0, 'Re')
ax.set_ylabel('Im')
> Text(0, 0.5, 'Im')
plt.show()

import sys
sys.path.insert(1, 'libs/')

import numpy as np
import scipy as sc
from scipy import io
import dynfc as dyn
import seaborn as sns
import matplotlib.pyplot as plt

ts = sc.io.loadmat('data/ts.mat')['ts']
ts = ts

RSsig = np.zeros((ts.shape[0],ts.shape[1],1))
RSsig[:,:,0] = ts

Phases, syncConn, leidaArray = dyn.run_multiPat(RSsig)
> Signal filtered.
> Phases obtained.
> Matrices obtained.
> Routine finished for patient no. 1.
mat1 = syncConn[:,:,0,0]

aa = plt.figure(figsize = [7,6])
ax = sns.heatmap(mat1, 
                 cmap = "RdBu_r", 
                 vmin = -1, 
                 vmax = 1, 
                 square = True, 
                 cbar = True)
ax.axis('off')
> (0.0, 200.0, 200.0, 0.0)
ax.tick_params(left=False, bottom=False)
plt.show()

aa = plt.figure(figsize = (12/50,4))
ax = sns.heatmap(leidaArray[:,0,]/max(abs(leidaArray[:,0,])), 
                 cmap = "RdBu_r", 
                 vmin = -1, 
                 vmax = 1, 
                 square = False, 
                 cbar = False)
ax.axis('off')
> (0.0, 1.0, 1180.0, 0.0)
plt.show()

This document was prepared on 2021-02-15.

Package References

report::cite_packages(sessionInfo())
  • JJ Allaire and Yihui Xie and Jonathan McPherson and Javier Luraschi and Kevin Ushey and Aron Atkins and Hadley Wickham and Joe Cheng and Winston Chang and Richard Iannone (2020). rmarkdown: Dynamic Documents for R. R package version 2.6. URL https://rmarkdown.rstudio.com.
  • Kevin Ushey, JJ Allaire and Yuan Tang (2021). reticulate: Interface to ‘Python’. R package version 1.18-9007. https://github.com/rstudio/reticulate
  • R Core Team (2020). R: A language and environment for statistical computing. R Foundation for Statistical Computing, Vienna, Austria. URL https://www.R-project.org/.
LS0tCnRpdGxlOiAnKipSZXN1bHRzIFRlbXBsYXRlKionCnN1YnRpdGxlOiBBIFN1YnRpdGxlCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IGNlcnVsZWFuCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiBubwogICAgZGZfcHJpbnQ6IGthYmxlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogIHdvcmRfZG9jdW1lbnQ6CiAgICByZWZlcmVuY2VfZG9jeDogdXRpbHMvVGVtcGxhdGVfV29yZC5kb2N4CiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICB0b2M6IG5vCiAgICB0b2NfZGVwdGg6IDMKICAgIGRmX3ByaW50OiBrYWJsZQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICBybWFya2Rvd246Omh0bWxfdmlnbmV0dGU6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAzCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogJzInCiAgICBsYXRleF9lbmdpbmU6IHhlbGF0ZXgKZWRpdG9yX29wdGlvbnM6CiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQpiaWJsaW9ncmFwaHk6IHV0aWxzL2JpYmxpb2dyYXBoeS5iaWIKY3NsOiB1dGlscy9hcGEuY3NsCi0tLQoKCjwhLS0gCiEhISEgSU1QT1JUQU5UOiBydW4gYHNvdXJjZSgidXRpbHMvcmVuZGVyLlIiKWAgdG8gcHVibGlzaCBpbnN0ZWFkIG9mIGNsaWNraW5nIG9uICdLbml0JwotLT4KCiMjIFBhY2thZ2VzCgoKCmBgYHtyIHNldHVwLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPVRSVUUsIGluY2x1ZGU9RkFMU0V9CnNvdXJjZSgidXRpbHMvY29uZmlnLlIiKSAgCgpmYXN0IDwtIEZBTFNFICAjIE1ha2UgdGhpcyBmYWxzZSB0byBza2lwIHRoZSBjaHVua3MKYGBgCgoKCiMgSW50cm9kdWN0aW9uCgpgYGB7ciBiYWRnZXMsIGVjaG89RkFMU0UsIG1lc3NhZ2U9VFJVRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9CiMgVGhpcyBjaHVuayBpcyBhIGJpdCBjb21wbGV4IHNvIGRvbid0IHdvcnJ5IGFib3V0IGl0OiBpdCdzIG1hZGUgdG8gYWRkIGJhZGdlcyB0byB0aGUgSFRNTCB2ZXJzaW9ucwojIE5PVEU6IFlvdSBoYXZlIHRvIHJlcGxhY2UgdGhlIGxpbmtzIGFjY29yZGluZ2x5IHRvIGhhdmUgd29ya2luZyAiYnV0dG9ucyIgb24gdGhlIEhUTUwgdmVyc2lvbnMKaWYgKCFrbml0cjo6aXNfbGF0ZXhfb3V0cHV0KCkgJiYga25pdHI6OmlzX2h0bWxfb3V0cHV0KCkpIHsKICBjYXQoIiFbQnVpbGRdKGh0dHBzOi8vZ2l0aHViLmNvbS9SZWFsaXR5QmVuZGluZy9UZW1wbGF0ZVJlc3VsdHMvd29ya2Zsb3dzL0J1aWxkL2JhZGdlLnN2ZykKICAgICAgWyFbV2Vic2l0ZV0oaHR0cHM6Ly9pbWcuc2hpZWxkcy5pby9iYWRnZS9yZXBvLVJlYWRtZS0yMTk2RjMpXShodHRwczovL2dpdGh1Yi5jb20vUmVhbGl0eUJlbmRpbmcvVGVtcGxhdGVSZXN1bHRzKQogICAgICBbIVtXZWJzaXRlXShodHRwczovL2ltZy5zaGllbGRzLmlvL2JhZGdlL3Zpc2l0LXdlYnNpdGUtRTkxRTYzKV0oaHR0cHM6Ly9yZWFsaXR5YmVuZGluZy5naXRodWIuaW8vVGVtcGxhdGVSZXN1bHRzLykKICAgICAgWyFbV2Vic2l0ZV0oaHR0cHM6Ly9pbWcuc2hpZWxkcy5pby9iYWRnZS9kb3dubG9hZC0uZG9jeC1GRjU3MjIpXShodHRwczovL2dpdGh1Yi5jb20vUmVhbGl0eUJlbmRpbmcvVGVtcGxhdGVSZXN1bHRzL3Jhdy9tYWluL3dvcmRfYW5kX3BkZi9TdXBwbGVtZW50YXJ5TWF0ZXJpYWxzLmRvY3gpCiAgICAgIFshW1dlYnNpdGVdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2Uvc2VlLS5wZGYtRkY5ODAwKV0oaHR0cHM6Ly9naXRodWIuY29tL1JlYWxpdHlCZW5kaW5nL1RlbXBsYXRlUmVzdWx0cy9ibG9iL21haW4vd29yZF9hbmRfcGRmL1N1cHBsZW1lbnRhcnlNYXRlcmlhbHMucGRmKSIpCn0KYGBgCgoKIyBTbGlkaW5nIHdpbmRvd3MKCmBgYHtweXRob259CmltcG9ydCBzeXMKc3lzLnBhdGguaW5zZXJ0KDEsICdsaWJzLycpCgppbXBvcnQgZHluZmMgYXMgZHluCmltcG9ydCBudW1weSBhcyBucApmcm9tIG51bXB5LnJhbmRvbSBpbXBvcnQgc2VlZCwgcmFuZAppbXBvcnQgc2NpcHkgYXMgc2MKZnJvbSBzY2lweSBpbXBvcnQgaW8KaW1wb3J0IHNlYWJvcm4gYXMgc25zCmltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBwbHQKaW1wb3J0IG1hdHBsb3RsaWIuY2Jvb2sgYXMgY2Jvb2sKaW1wb3J0IG1hdHBsb3RsaWIuY20gYXMgY20KaW1wb3J0IG1hdHBsb3RsaWIucGF0Y2hlcyBhcyBwYXRjaGVzCgpmb250ID0geyd3ZWlnaHQnIDogJ3JlZ3VsYXInLAogICAgICAgICdzaXplJyAgIDogMjR9CnBsdC5yYygnZm9udCcsICoqZm9udCkKCnRzID0gc2MuaW8ubG9hZG1hdCgnZGF0YS90cy5tYXQnKVsndHMnXQp0cyA9IHRzLnRyYW5zcG9zZSgpCgpjb3JyX21hdHMsIGlkeCA9IGR5bi5jb3JyX3NsaWRlKHRzLDMwMCw1MCkKCmlkeC5zaGFwZQoKYSA9IFsxLDEsMSwxLDEuNl0KCmZpZyxheCA9IHBsdC5zdWJwbG90cygxKQpmaWcuc2V0X2ZpZ2hlaWdodCgxMCkKZmlnLnNldF9maWd3aWR0aCgyMCkKcGx0LnN0eWxlLnVzZSgndGFibGVhdS1jb2xvcmJsaW5kMTAnKQpmb3IgaSBpbiByYW5nZSg1KToKICAgIAogICAgcGx0LnBsb3QoMippKmFbaV0gKyB0c1tpLF0vMS40KSAgIAogICAgCnBsdC54bGFiZWwoJ1RpbWUgW1RSc10nKQpwbHQueWxhYmVsKCdCT0xEJykKYXgudGlja19wYXJhbXMobGVmdD1GYWxzZSkKYXguc2V0X3l0aWNrbGFiZWxzKFtdKQpheC5zZXRfeWxpbSgtMywxNS40KQpheC5zZXRfeGxpbSgwLDEyMDApCnJlY3QgPSBwYXRjaGVzLlJlY3RhbmdsZSgoaWR4WzBdLC0yLjgpLDMwMCwxOCxsaW5ld2lkdGg9NCxlZGdlY29sb3I9JyM1OTU5NTknLGZhY2Vjb2xvcj0nbm9uZScpCmF4LmFkZF9wYXRjaChyZWN0KQpyZWN0ID0gcGF0Y2hlcy5SZWN0YW5nbGUoKGlkeFs1XSwtMi44KSwzMDAsMTgsbGluZXdpZHRoPTQsZWRnZWNvbG9yPScjQTU2QjZCJyxmYWNlY29sb3I9J25vbmUnKQpheC5hZGRfcGF0Y2gocmVjdCkKcmVjdCA9IHBhdGNoZXMuUmVjdGFuZ2xlKChpZHhbOV0sLTIuOCksMzAwLDE4LGxpbmV3aWR0aD00LGVkZ2Vjb2xvcj0nI0NFM0UzRScsZmFjZWNvbG9yPSdub25lJykKYXguYWRkX3BhdGNoKHJlY3QpCnJlY3QgPSBwYXRjaGVzLlJlY3RhbmdsZSgoaWR4WzE2XSwtMi44KSwzMDAsMTgsbGluZXdpZHRoPTQsZWRnZWNvbG9yPScjRkYwMDAwJyxmYWNlY29sb3I9J25vbmUnKQpheC5hZGRfcGF0Y2gocmVjdCkKcGx0LnNob3coKQpgYGAKCmBgYHtweXRob259CmltcG9ydCBzeXMKc3lzLnBhdGguaW5zZXJ0KDEsICdsaWJzLycpCgppbXBvcnQgZHluZmMgYXMgZHluCmltcG9ydCBudW1weSBhcyBucApmcm9tIG51bXB5LnJhbmRvbSBpbXBvcnQgc2VlZCwgcmFuZAppbXBvcnQgc2NpcHkgYXMgc2MKZnJvbSBzY2lweSBpbXBvcnQgaW8KaW1wb3J0IHNlYWJvcm4gYXMgc25zCmltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBwbHQKaW1wb3J0IG1hdHBsb3RsaWIuY2Jvb2sgYXMgY2Jvb2sKaW1wb3J0IG1hdHBsb3RsaWIuY20gYXMgY20KaW1wb3J0IG1hdHBsb3RsaWIucGF0Y2hlcyBhcyBwYXRjaGVzCgphYSA9IHBsdC5maWd1cmUoZmlnc2l6ZSA9IFs2LDZdKQpheCA9IHNucy5oZWF0bWFwKGNvcnJfbWF0c1s6LDosMF0sIAogICAgICAgICAgICAgICAgIGNtYXAgPSAiUmRCdV9yIiwgCiAgICAgICAgICAgICAgICAgdm1pbiA9IC0xLCAKICAgICAgICAgICAgICAgICB2bWF4ID0gMSwgCiAgICAgICAgICAgICAgICAgc3F1YXJlID0gVHJ1ZSwgCiAgICAgICAgICAgICAgICAgY2JhciA9IEZhbHNlKQpheC5heGlzKCdvZmYnKQpheC50aWNrX3BhcmFtcyhsZWZ0PUZhbHNlLCBib3R0b209RmFsc2UpCiAgICAKcGx0LnNob3coKQoKYWEgPSBwbHQuZmlndXJlKGZpZ3NpemUgPSBbNiw2XSkKYXggPSBzbnMuaGVhdG1hcChjb3JyX21hdHNbOiw6LDVdLCAKICAgICAgICAgICAgICAgICBjbWFwID0gIlJkQnVfciIsIAogICAgICAgICAgICAgICAgIHZtaW4gPSAtMSwgCiAgICAgICAgICAgICAgICAgdm1heCA9IDEsIAogICAgICAgICAgICAgICAgIHNxdWFyZSA9IFRydWUsIAogICAgICAgICAgICAgICAgIGNiYXIgPSBGYWxzZSkKYXguYXhpcygnb2ZmJykKYXgudGlja19wYXJhbXMobGVmdD1GYWxzZSwgYm90dG9tPUZhbHNlKQogICAgCnBsdC5zaG93KCkKCmFhID0gcGx0LmZpZ3VyZShmaWdzaXplID0gWzYsNl0pCmF4ID0gc25zLmhlYXRtYXAoY29ycl9tYXRzWzosOiw5XSwgCiAgICAgICAgICAgICAgICAgY21hcCA9ICJSZEJ1X3IiLCAKICAgICAgICAgICAgICAgICB2bWluID0gLTEsIAogICAgICAgICAgICAgICAgIHZtYXggPSAxLCAKICAgICAgICAgICAgICAgICBzcXVhcmUgPSBUcnVlLCAKICAgICAgICAgICAgICAgICBjYmFyID0gRmFsc2UpCmF4LmF4aXMoJ29mZicpCmF4LnRpY2tfcGFyYW1zKGxlZnQ9RmFsc2UsIGJvdHRvbT1GYWxzZSkKICAgIApwbHQuc2hvdygpCgphYSA9IHBsdC5maWd1cmUoZmlnc2l6ZSA9IFs2LDZdKQpheCA9IHNucy5oZWF0bWFwKGNvcnJfbWF0c1s6LDosMTZdLCAKICAgICAgICAgICAgICAgICBjbWFwID0gIlJkQnVfciIsIAogICAgICAgICAgICAgICAgIHZtaW4gPSAtMSwgCiAgICAgICAgICAgICAgICAgdm1heCA9IDEsIAogICAgICAgICAgICAgICAgIHNxdWFyZSA9IFRydWUsIAogICAgICAgICAgICAgICAgIGNiYXIgPSBGYWxzZSkKYXguYXhpcygnb2ZmJykKYXgudGlja19wYXJhbXMobGVmdD1GYWxzZSwgYm90dG9tPUZhbHNlKQogICAgCnBsdC5zaG93KCkKCmBgYAoKIyBDb2ZsdWN0dWF0aW9ucwoKYGBge3B5dGhvbn0KaW1wb3J0IHN5cwpzeXMucGF0aC5pbnNlcnQoMSwgJ2xpYnMvJykKCmltcG9ydCBudW1weSBhcyBucAppbXBvcnQgc2NpcHkgYXMgc2MKZnJvbSBzY2lweSBpbXBvcnQgaW8KaW1wb3J0IGR5bmZjIGFzIGR5bgppbXBvcnQgc2VhYm9ybiBhcyBzbnMKaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdAoKdHMgPSBzYy5pby5sb2FkbWF0KCdkYXRhL3RzLm1hdCcpWyd0cyddCnRzID0gdHMudHJhbnNwb3NlKCkKCm1hdDEsIHJzcyA9IGR5bi5jb3JyX3NsaWRlKHRzLDI0KQptYXQxID0gbWF0MVs6LDosMF0KCmFhID0gcGx0LmZpZ3VyZShmaWdzaXplID0gWzYsNl0pCmF4ID0gc25zLmhlYXRtYXAobWF0MSwgCiAgICAgICAgICAgICAgICAgY21hcCA9ICJSZEJ1X3IiLCAKICAgICAgICAgICAgICAgICB2bWluID0gLTEsIAogICAgICAgICAgICAgICAgIHZtYXggPSAxLCAKICAgICAgICAgICAgICAgICBzcXVhcmUgPSBGYWxzZSwgCiAgICAgICAgICAgICAgICAgY2JhciA9IFRydWUpCmF4LmF4aXMoJ29mZicpCmF4LnRpY2tfcGFyYW1zKGxlZnQ9RmFsc2UsIGJvdHRvbT1GYWxzZSkKcGx0LnNob3coKQoKdXB0ID0gbnAudHJpdV9pbmRpY2VzKG1hdDEuc2hhcGVbMF0sIGsgPSAxKQp2ZWMgPSAobWF0MVt1cHRdKQoKdG9QbG90ID0gbnAuemVyb3MoKHZlYy5zaGFwZVswXSwxKSkKdG9QbG90WzosMF0gPSB2ZWMKCmFhID0gcGx0LmZpZ3VyZShmaWdzaXplID0gKDEyLzUwLDQpKQpheCA9IHNucy5oZWF0bWFwKHRvUGxvdFs6LDA6MV0sIAogICAgICAgICAgICAgICAgIGNtYXAgPSAiUmRCdV9yIiwgCiAgICAgICAgICAgICAgICAgdm1pbiA9IC0xLCAKICAgICAgICAgICAgICAgICB2bWF4ID0gMSwgCiAgICAgICAgICAgICAgICAgc3F1YXJlID0gRmFsc2UsIAogICAgICAgICAgICAgICAgIGNiYXIgPSBGYWxzZSkKYXguYXhpcygnb2ZmJykKcGx0LnNob3coKQoKZWRnZXNfc2VyaWVzLCBjb3JyX21hdHMsIHJzcyA9IGR5bi5jb2ZsdWN0KHRzLCAyNCkKCmFhID0gcGx0LmZpZ3VyZShmaWdzaXplID0gKDEyLDQpKQpheCA9IHNucy5oZWF0bWFwKGVkZ2VzX3NlcmllcywgCiAgICAgICAgICAgICAgICAgY21hcCA9ICJSZEJ1X3IiLCAKICAgICAgICAgICAgICAgICB2bWluID0gLTEsIAogICAgICAgICAgICAgICAgIHZtYXggPSAxLCAKICAgICAgICAgICAgICAgICBzcXVhcmUgPSBGYWxzZSwgCiAgICAgICAgICAgICAgICAgY2JhciA9IEZhbHNlKQpheC5heGlzKCdvZmYnKQpwbHQuc2hvdygpCmBgYAoKI1BoYXNlIGRpZmZlcmVuY2UKCmBgYHtweXRob259CmltcG9ydCBzeXMKc3lzLnBhdGguaW5zZXJ0KDEsICdsaWJzLycpCgppbXBvcnQgbnVtcHkgYXMgbnAKaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdAppbXBvcnQgbWF0cGxvdGxpYi5wYXRjaGVzIGFzIHBhdGNoZXMKZnJvbSBtcGxfdG9vbGtpdHMubXBsb3QzZCBpbXBvcnQgQXhlczNECgp0aGV0YSA9IG5wLmxpbnNwYWNlKDAqbnAucGksIDgqbnAucGksIDEwMCkKdGltZSA9IG5wLmxpbnNwYWNlKDAsIDgsIDEwMCkKeTEgPSBucC5zaW4odGhldGEpCngxID0gbnAuY29zKHRoZXRhKQp5MiA9IG5wLnNpbih0aGV0YSArIG5wLnBpLzIpCngyID0gbnAuY29zKHRoZXRhICsgbnAucGkvMikKciA9IHRpbWUvbnAubWF4KHRpbWUpCm9uZXMgPSBucC5vbmVzKHRpbWUuc2hhcGVbMF0pCgpmaWcgPSBwbHQuZmlndXJlKCkKYXggPSBmaWcuYWRkX3N1YnBsb3QocHJvamVjdGlvbj0nM2QnKQpwbHQuc3R5bGUudXNlKCdjbGFzc2ljJykKCmF4LnBsb3QodGltZSwgeDEsIHkxLCBjb2xvciA9ICcjNjcwMDFmJywgbGluZXdpZHRoPTIpCmF4LnBsb3QodGltZSxvbmVzLHkxLCBsaW5lc3R5bGUgPSAnLS0nLCBjb2xvciA9ICcjMGYwZjBmJykKYXgucGxvdCh0aW1lLHgxLC1vbmVzLCBsaW5lc3R5bGUgPSAnLS0nLCBjb2xvciA9ICcjMGYwZjBmJykKYXgucXVpdmVyKHRpbWUsMCwwLDAsIDAuOTkqeDEsIDAuOTkqeTEsIAogICAgICAgICAgbGVuZ3RoID0gMC45LCAKICAgICAgICAgIG5vcm1hbGl6ZSA9IEZhbHNlLCAKICAgICAgICAgIGFycm93X2xlbmd0aF9yYXRpbyA9IDAuMSwgCiAgICAgICAgICBhbHBoYSA9IDAuNCwgCiAgICAgICAgICBjb2xvciA9ICcjMDUzMDYxJykKYXgudGV4dCgwLjUsIDEsIDAuNSwgcickXHNpbihcdGhldGEpJCcsIGZvbnRzaXplID0gMjApCmF4LnRleHQoMC41LCAtMSwgLTEsIHInJFxjb3MoXHRoZXRhKSQnLCBmb250c2l6ZSA9IDIwKQpheC5zZXRfeGxhYmVsKCdUaW1lJykKYXguc2V0X3lsYWJlbCgnUmUnKQpheC5zZXRfemxhYmVsKCdJbScpCmF4LnNldF94bGltKDAsOCkKYXguc2V0X3lsaW0oLTEsMSkKYXguc2V0X3psaW0oLTEsMSkKcGx0LnNob3coKQoKY29sb3JzMSA9IHBsdC5jbS5SZWRzKG5wLmFyYW5nZSgwLDEsMC4wMSkpCmNvbG9yczFbOiwtMV0gPSBucC5hcmFuZ2UoMCwxLDAuMDEpCgpjb2xvcnMyID0gcGx0LmNtLkJsdWVzKG5wLmFyYW5nZSgwLDEsMC4wMSkpCmNvbG9yczJbOiwtMV0gPSBucC5hcmFuZ2UoMCwxLDAuMDEpCgpmaWcgPSBwbHQuZmlndXJlKGZpZ3NpemUgPSAoMTIsOCkpCmF4ID0gZmlnLmFkZF9zdWJwbG90KHByb2plY3Rpb249JzNkJykKcGx0LnN0eWxlLnVzZSgnY2xhc3NpYycpCgpheC5zY2F0dGVyKHRpbWUsb25lcyxyKnkxLCBjb2xvciA9IGNvbG9yczEsIG1hcmtlciA9ICIsIiwgcyA9IDMpCmF4LnNjYXR0ZXIodGltZSxyKngxLC1vbmVzLCBjb2xvciA9IGNvbG9yczEsIG1hcmtlciA9ICIsIiwgcyA9IDMpCmF4LnNjYXR0ZXIodGltZSxvbmVzLHIqeTIsIGNvbG9yID0gY29sb3JzMiwgbWFya2VyID0gIiwiLCBzID0gMykKYXguc2NhdHRlcih0aW1lLHIqeDIsLW9uZXMsIGNvbG9yID0gY29sb3JzMiwgbWFya2VyID0gIiwiLCBzID0gMykKI2F4LnBsb3QodGltZSxyKngyLC1vbmVzLCBsaW5lc3R5bGUgPSAnLS0nLCBjb2xvciA9IGNvbG9yczJbLTEwLDpdKQpheC5xdWl2ZXIodGltZSwwLDAsMCwgMC45OSpyKngxLCAwLjk5KnIqeTEsIAogICAgICAgICAgbGVuZ3RoID0gMC45LCAKICAgICAgICAgIG5vcm1hbGl6ZSA9IEZhbHNlLCAKICAgICAgICAgIGFycm93X2xlbmd0aF9yYXRpbyA9IDAuMSwgCiAgICAgICAgICBhbHBoYSA9IDEsIAogICAgICAgICAgY29sb3IgPSBjb2xvcnMxKQpheC5xdWl2ZXIodGltZSwwLDAsMCwgMC45OSpyKngyLCAwLjk5KnIqeTIsIAogICAgICAgICAgbGVuZ3RoID0gMC45LCAKICAgICAgICAgIG5vcm1hbGl6ZSA9IEZhbHNlLCAKICAgICAgICAgIGFycm93X2xlbmd0aF9yYXRpbyA9IDAuMSwgCiAgICAgICAgICBhbHBoYSA9IDEsIAogICAgICAgICAgY29sb3IgPSBjb2xvcnMyKQpheC50ZXh0KDAuNSwgMSwgMC40LCByJyRBKHQpJCAkXHNpbihcdGhldGEpJCcsIGZvbnRzaXplID0gMjApCmF4LnRleHQoMC41LCAtMC45LCAtMSwgcickQSh0KSQgJFxjb3MoXHRoZXRhKSQnLCBmb250c2l6ZSA9IDIwKQpheC5zZXRfeGxhYmVsKCdUaW1lJykKYXguc2V0X3lsYWJlbCgnUmUnKQpheC5zZXRfemxhYmVsKCdJbScpCmF4LnNldF94bGltKDAsOCkKYXguc2V0X3lsaW0oLTEsMSkKYXguc2V0X3psaW0oLTEsMSkKcGx0LnNob3coKQoKeDFfdmVjID0geDEKeDFfdmVjID0geDFfdmVjWzk5XQp5MV92ZWMgPSB5MQp5MV92ZWMgPSB5MV92ZWNbOTldCgp4Ml92ZWMgPSB4Mgp4Ml92ZWMgPSB4Ml92ZWNbOTldCnkyX3ZlYyA9IHkyCnkyX3ZlYyA9IHkyX3ZlY1s5OV0KCngsIHkgPSAwLjAsIDAuMAoKZmlnLGF4ID0gcGx0LnN1YnBsb3RzKDEpCmZpZy5zZXRfZmlnaGVpZ2h0KDYpCmZpZy5zZXRfZmlnd2lkdGgoNykKYXguc2NhdHRlcihyKngxLHIqeTEsIGNvbG9yID0gY29sb3JzMSwgbWFya2VyID0gIi4iLCBzID0gMTAwKQpheC5zY2F0dGVyKHIqeDIscip5MiwgY29sb3IgPSBjb2xvcnMyLCBtYXJrZXIgPSAiLiIsIHMgPSAxMDApCmF4LmFycm93KDAsMCx4MV92ZWMseTFfdmVjLCB3aWR0aCA9IDAuMDE1LCBjb2xvciA9IGNvbG9yczFbLTEsOl0sIGhlYWRfd2lkdGggPSAwLjEpCmF4LmFycm93KDAsMCx4Ml92ZWMseTJfdmVjLCB3aWR0aCA9IDAuMDE1LCBjb2xvciA9IGNvbG9yczJbLTEsOl0sIGhlYWRfd2lkdGggPSAwLjEpCmF4LmFkZF9wYXRjaChwYXRjaGVzLkFyYygoeCx5KSwgMi4zLCAyLjMsIHRoZXRhMT0wLjAsIHRoZXRhMj05MC4wLCBsaW5lc3R5bGUgPSAnLS0nKSkKYXgudGV4dCgwLjcsMSwgcickXG1hdGhjYWx7XERlbHRhXHZhcnBoaSA9IFxmcmFje1xwaX17Mn19JCcsIGZvbnRzaXplID0gMjQpCmF4LnRleHQoMS4xOCp4MV92ZWMseTFfdmVjLCByJyRcbWF0aGNhbHtcdmFycGhpfV97MX0kJywgZm9udHNpemUgPSAyMCkKYXgudGV4dCh4Ml92ZWMsMS4yMip5Ml92ZWMsIHInJFxtYXRoY2Fse1x2YXJwaGl9X3syfSQnLCBmb250c2l6ZSA9IDIwKQpheC5zZXRfeGxpbSgtMS4zNSwxLjM1KQpheC5zZXRfeWxpbSgtMS4zNSwxLjM1KQpheC5zZXRfeGxhYmVsKCdSZScpCmF4LnNldF95bGFiZWwoJ0ltJykKcGx0LnNob3coKQpgYGAKCmBgYHtweXRob259CmltcG9ydCBzeXMKc3lzLnBhdGguaW5zZXJ0KDEsICdsaWJzLycpCgppbXBvcnQgbnVtcHkgYXMgbnAKaW1wb3J0IHNjaXB5IGFzIHNjCmZyb20gc2NpcHkgaW1wb3J0IGlvCmltcG9ydCBkeW5mYyBhcyBkeW4KaW1wb3J0IHNlYWJvcm4gYXMgc25zCmltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBwbHQKCnRzID0gc2MuaW8ubG9hZG1hdCgnZGF0YS90cy5tYXQnKVsndHMnXQp0cyA9IHRzCgpSU3NpZyA9IG5wLnplcm9zKCh0cy5zaGFwZVswXSx0cy5zaGFwZVsxXSwxKSkKUlNzaWdbOiw6LDBdID0gdHMKClBoYXNlcywgc3luY0Nvbm4sIGxlaWRhQXJyYXkgPSBkeW4ucnVuX211bHRpUGF0KFJTc2lnKQoKbWF0MSA9IHN5bmNDb25uWzosOiwwLDBdCgphYSA9IHBsdC5maWd1cmUoZmlnc2l6ZSA9IFs3LDZdKQpheCA9IHNucy5oZWF0bWFwKG1hdDEsIAogICAgICAgICAgICAgICAgIGNtYXAgPSAiUmRCdV9yIiwgCiAgICAgICAgICAgICAgICAgdm1pbiA9IC0xLCAKICAgICAgICAgICAgICAgICB2bWF4ID0gMSwgCiAgICAgICAgICAgICAgICAgc3F1YXJlID0gVHJ1ZSwgCiAgICAgICAgICAgICAgICAgY2JhciA9IFRydWUpCmF4LmF4aXMoJ29mZicpCmF4LnRpY2tfcGFyYW1zKGxlZnQ9RmFsc2UsIGJvdHRvbT1GYWxzZSkKcGx0LnNob3coKQoKYWEgPSBwbHQuZmlndXJlKGZpZ3NpemUgPSAoMTIvNTAsNCkpCmF4ID0gc25zLmhlYXRtYXAobGVpZGFBcnJheVs6LDAsXS9tYXgoYWJzKGxlaWRhQXJyYXlbOiwwLF0pKSwgCiAgICAgICAgICAgICAgICAgY21hcCA9ICJSZEJ1X3IiLCAKICAgICAgICAgICAgICAgICB2bWluID0gLTEsIAogICAgICAgICAgICAgICAgIHZtYXggPSAxLCAKICAgICAgICAgICAgICAgICBzcXVhcmUgPSBGYWxzZSwgCiAgICAgICAgICAgICAgICAgY2JhciA9IEZhbHNlKQpheC5heGlzKCdvZmYnKQpwbHQuc2hvdygpCmBgYAoKClRoaXMgZG9jdW1lbnQgd2FzIHByZXBhcmVkIG9uIGByIGZvcm1hdChTeXMuRGF0ZSgpKWAuIAoKCiMgUGFja2FnZSBSZWZlcmVuY2VzCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30KcmVwb3J0OjpjaXRlX3BhY2thZ2VzKHNlc3Npb25JbmZvKCkpCmBgYAoK